
/*
*********************************
	  SF2D Engine
*********************************

	By Julian Williams
	August 8, 2010
**********************************

	Description:

		Path Finding Class that is
	used for Ai Navigation around
	the map
***********************************
*/


#include <iostream>
#include <vector>
#include <list>

using namespace std;

#include "entity_factory.h"
#include "path_finder.h"
#include "helper.h"
#include "levels.h"


//global path finder
Path_Finder Pather;


Path_Finder::Path_Finder()
{
	map_width = 0;
	map_height = 0;

	pEngine = new MicroPather( this, 1200, 4);	// Use a very small memory block to stress the pather
}

Path_Finder::~Path_Finder()
{
	delete pEngine;
	pEngine = NULL;
}

void Path_Finder::SetGridWidth(int width )
{
	map_width = width;
}
void Path_Finder::SetGridHeight(int height )
{
	map_height = height;
}



void Path_Finder::Setup(int width, int height)
{
	//Setup map dimentions for pather
	SetGridWidth(width);
	SetGridHeight(height);

	//resize passable array
	this->passable.resize(width, height);
	this->pEngine->Reset();
}//EoF



//Solves a path from one point to another, taking in 4 params for 2 x/y positions
int Path_Finder::SolvePath(int start_x, int start_y, int end_x, int end_y, vector <void *> &path, float &total_cost)
{

	//convert positions to 'states' that the micropather understands
	void* start_state = XYToNode(start_x, start_y);
	void* end_state   = XYToNode(end_x, end_y);

	//cout << int(start_state) << ", "<< int(end_state) << endl;

	int result = pEngine->Solve(start_state, end_state, &path, &total_cost);
	return result;

}



//convert to/from Nodes to positons
void Path_Finder::NodeToXY( void* node, int* x, int* y ) 
{
		int index = (int)node;
		*y = index / map_width;
		*x = index - (*y) * map_width;
}

void* Path_Finder::XYToNode( int x, int y )
{
	return (void*) ( y*map_width + x );
}






GridNode Path_Finder::NodeToGrid( void* node )
{
	 //  MP_UPTR stateNumber = reinterpret_cast<MP_UPTR>(state);
	//((testStructure*)ptr)->a = 5;

	GridNode *g_nodePtr = reinterpret_cast<GridNode*>(node);
	GridNode g_node = *g_nodePtr;
	return g_node;
}//EoF

void* Path_Finder::GridToNode( GridNode &grid_node)
{
	return (void*) (&grid_node);
}






float Path_Finder::LeastCostEstimate( void* nodeStart, void* nodeEnd ) 
{
		int xStart, yStart, xEnd, yEnd;

		NodeToXY( nodeStart, &xStart, &yStart );
		NodeToXY( nodeEnd, &xEnd, &yEnd );

		/* Compute the minimum path cost using distance measurement. It is possible
		   to compute the exact minimum path using the fact that you can move only 
		   on a straight line or on a diagonal, and this will yield a better result.
		*/
		int dx = xStart - xEnd;
		int dy = yStart - yEnd;
		return (float) sqrtFast( (double)(dx*dx) + (double)(dy*dy) );
}


int Path_Finder::PassableTest( int nx, int ny ) 
{

		if (  nx < 0 || nx > map_width || 
			  ny < 0 || ny > map_height  )
		{
			//int index = ny*map_width +nx;
			cout << "Invalid PassabliltyTest.\n"
				 << nx << ", " << ny << endl
				 << map_width << ", " << map_height << endl;

			return -1;
		}
		
	//	int arraySize = sizeof(passable.) / sizeof(passable[ 0 ][ 0 ]);
		//cout << arraySize << endl;
		//system("PAUSE");
			int c = passable[ nx ][ ny ];

		return c;
}//EoF





//Get/Set from the passable Dynamic array
void Path_Finder::Set_Passable(int x, int y, int value)
{
	if((x < 0) || (x >= map_width) ||
	   (y < 0) || (y >= map_height))
	{
		cout << "[PATH] - Set_Passable(...) received invalid arguments - " << x << ", " << y << endl;
		cout << "File: " << __FILE__ << endl;
		cout << "Line: " << __LINE__ << endl;
		return;
	}

	passable[x][y] = value;
}

int Path_Finder::Get_Passable(int x, int y)
{
	return passable[x][y];
}


void Path_Finder::PrintStateInfo( void* node ) 
{
		int x, y;
		NodeToXY( node, &x, &y );
		printf( "(%d, %d)", x, y );
}//EoF



void Path_Finder::AdjacentCost( void* node, std::vector< StateCost > *neighbors ) 
{
		int x, y;
		/* Saved for future use
		const int dx[8] = { 1, 1, 0, -1, -1, -1, 0, 1 };
		const int dy[8] = { 0, 1, 1, 1, 0, -1, -1, -1 };
		//const float cost[8] = { 1.0f,  FLT_MAX , 1.0f,  FLT_MAX , 1.0f,  FLT_MAX , 1.0f,  FLT_MAX };
		const float cost[8] = { 1.0f, 1.41f, 1.0f, 1.41f, 1.0f, 1.41f, 1.0f, 1.41f };
		*/

		//Define non diagonal movement only
		const int dx[4] = { 1,  0, -1,  0 };
		const int dy[4] = { 0,  1,  0, -1 };
		const float cost[4] = { 1.0f,  1.0f,  1.0f,  1.0f };


		NodeToXY( node, &x, &y );


		for( int i=0; i<4; ++i ) 
		{
			int nx = x + dx[i];
			int ny = y + dy[i];

			int  pass = PassableTest( nx, ny );
			if ( pass >= 0 ) 
			{
				if (( pass == Triggers::OPEN ) || (pass ==  Triggers::NOT_BUILDABLE) ||
					( pass ==  Triggers::CREEP_SPAWN) || (pass ==  Triggers::CREEP_EXIT))

				{
					// Normal floor
					StateCost nodeCost = { XYToNode( nx, ny ), cost[i] };
					neighbors->push_back( nodeCost );
				}
				else
				{
					// Normal floor
					StateCost nodeCost = { XYToNode( nx, ny ), FLT_MAX };
					neighbors->push_back( nodeCost );
				}
			}
				
		}


		/* Saved in case i break something 
		for( int i=0; i<8; ++i ) 
		{
			int nx = x + dx[i];
			int ny = y + dy[i];

			int  pass = PassableTest( nx, ny );
			if ( pass >= 0 ) 
			{
				if (( pass == Triggers::OPEN ) || (pass ==  Triggers::NOT_BUILDABLE) ||
					( pass ==  Triggers::CREEP_SPAWN) || (pass ==  Triggers::CREEP_EXIT))

				{
					// Normal floor
					StateCost nodeCost = { XYToNode( nx, ny ), cost[i] };
					neighbors->push_back( nodeCost );
				}
				else
				{
					// Normal floor
					StateCost nodeCost = { XYToNode( nx, ny ), FLT_MAX };
					neighbors->push_back( nodeCost );
				}
			}
				
		}
		*/

}//EoF